#include <linux/module.h>
#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/fs.h>
#include <linux/cdev.h>
#include <linux/device.h>
#include <linux/slab.h>
#include <linux/uaccess.h>
#include <linux/wait.h>
#include <linux/sched.h>
#include <linux/net.h>
#include <linux/in.h>
#include <linux/tcp.h>
#include <linux/socket.h>
#include <linux/kthread.h>
#include <linux/delay.h>
#include <linux/inet.h>
#include <linux/termios.h>
#include <asm/ioctls.h>
#include <linux/proc_fs.h>
#include <linux/seq_file.h>

#define VSERIAL_DEVICE_NAME "vserial_stj"
#define VSERIAL_CLASS_NAME "vserial_stj"
#define BUFFER_SIZE 4096
#define MAX_DEVICES 8  // 最大支持8个虚拟串口

MODULE_LICENSE("GPL");
MODULE_AUTHOR("Your Name");
MODULE_DESCRIPTION("Virtual Serial Port Driver");
MODULE_VERSION("1.0");

// 设备结构
typedef struct {
    struct cdev cdev;
    struct device *device;
    char buffer[BUFFER_SIZE];
    int read_pos;
    int write_pos;
    int data_size;
    wait_queue_head_t read_queue;
    spinlock_t buffer_lock;
    
    // 串口设置存储
    struct termios saved_termios;
    int settings_initialized;
    
    // TCP相关
    struct socket *tcp_socket;
    struct task_struct *tcp_thread;
    int tcp_connected;
    char tcp_ip[16];
    int tcp_port;
} vserial_device_t;

static int vserial_major = 0;
static struct class *vserial_class = NULL;
static vserial_device_t *vserial_devices[MAX_DEVICES] = {NULL};
static int device_count = 0;

// 参数
static char tcp_server_ip[16] = "127.0.0.1";
static int tcp_server_port = 5000;
static int num_devices = 1;  // 默认创建1个设备
static int reconnect_interval = 10;  // 默认重连间隔10秒

// 多设备参数（最多支持8个设备）
static char dev0_name[32] = "ttyV0";
static char dev0_ip[16] = "127.0.0.1";
static int dev0_port = 5000;
static char dev1_name[32] = "ttyV1";
static char dev1_ip[16] = "127.0.0.1";
static int dev1_port = 5001;
static char dev2_name[32] = "ttyV2";
static char dev2_ip[16] = "127.0.0.1";
static int dev2_port = 5002;
static char dev3_name[32] = "ttyV3";
static char dev3_ip[16] = "127.0.0.1";
static int dev3_port = 5003;
static char dev4_name[32] = "ttyV4";
static char dev4_ip[16] = "127.0.0.1";
static int dev4_port = 5004;
static char dev5_name[32] = "ttyV5";
static char dev5_ip[16] = "127.0.0.1";
static int dev5_port = 5005;
static char dev6_name[32] = "ttyV6";
static char dev6_ip[16] = "127.0.0.1";
static int dev6_port = 5006;
static char dev7_name[32] = "ttyV7";
static char dev7_ip[16] = "127.0.0.1";
static int dev7_port = 5007;

module_param_string(tcp_ip, tcp_server_ip, sizeof(tcp_server_ip), 0644);
module_param(tcp_server_port, int, 0644);
module_param(num_devices, int, 0644);
module_param(reconnect_interval, int, 0644);

// 多设备参数
module_param_string(dev0_name, dev0_name, sizeof(dev0_name), 0644);
module_param_string(dev0_ip, dev0_ip, sizeof(dev0_ip), 0644);
module_param(dev0_port, int, 0644);
module_param_string(dev1_name, dev1_name, sizeof(dev1_name), 0644);
module_param_string(dev1_ip, dev1_ip, sizeof(dev1_ip), 0644);
module_param(dev1_port, int, 0644);
module_param_string(dev2_name, dev2_name, sizeof(dev2_name), 0644);
module_param_string(dev2_ip, dev2_ip, sizeof(dev2_ip), 0644);
module_param(dev2_port, int, 0644);
module_param_string(dev3_name, dev3_name, sizeof(dev3_name), 0644);
module_param_string(dev3_ip, dev3_ip, sizeof(dev3_ip), 0644);
module_param(dev3_port, int, 0644);
module_param_string(dev4_name, dev4_name, sizeof(dev4_name), 0644);
module_param_string(dev4_ip, dev4_ip, sizeof(dev4_ip), 0644);
module_param(dev4_port, int, 0644);
module_param_string(dev5_name, dev5_name, sizeof(dev5_name), 0644);
module_param_string(dev5_ip, dev5_ip, sizeof(dev5_ip), 0644);
module_param(dev5_port, int, 0644);
module_param_string(dev6_name, dev6_name, sizeof(dev6_name), 0644);
module_param_string(dev6_ip, dev6_ip, sizeof(dev6_ip), 0644);
module_param(dev6_port, int, 0644);
module_param_string(dev7_name, dev7_name, sizeof(dev7_name), 0644);
module_param_string(dev7_ip, dev7_ip, sizeof(dev7_ip), 0644);
module_param(dev7_port, int, 0644);

// TCP连接
static int vserial_tcp_connect(vserial_device_t *dev)
{
    struct sockaddr_in addr;
    int ret;
    
    ret = sock_create(AF_INET, SOCK_STREAM, IPPROTO_TCP, &dev->tcp_socket);
    if (ret < 0) {
        printk(KERN_ERR "vserial: Failed to create socket\n");
        return ret;
    }
    
    memset(&addr, 0, sizeof(addr));
    addr.sin_family = AF_INET;
    addr.sin_port = htons(dev->tcp_port);
    ret = in4_pton(dev->tcp_ip, -1, (u8 *)&addr.sin_addr.s_addr, '\0', NULL);
    if (ret <= 0) {
        // 如果in4_pton不可用，使用in_aton
        addr.sin_addr.s_addr = in_aton(dev->tcp_ip);
        if (addr.sin_addr.s_addr == INADDR_NONE) {
            printk(KERN_ERR "vserial: Invalid IP address\n");
            sock_release(dev->tcp_socket);
            return -EINVAL;
        }
    }
    
    ret = dev->tcp_socket->ops->connect(dev->tcp_socket, 
                                       (struct sockaddr *)&addr, sizeof(addr), 0);
    if (ret < 0) {
        printk(KERN_ERR "vserial: Failed to connect to TCP server\n");
        sock_release(dev->tcp_socket);
        return ret;
    }
    
    dev->tcp_connected = 1;
    printk(KERN_INFO "vserial: Connected to TCP server %s:%d\n", 
           dev->tcp_ip, dev->tcp_port);
    return 0;
}

// TCP接收线程
static int vserial_tcp_thread(void *data)
{
    vserial_device_t *dev = (vserial_device_t *)data;
    struct msghdr msg;
    struct kvec iov;
    char tcp_buffer[BUFFER_SIZE];
    int ret;
    
    while (!kthread_should_stop()) {
        if (!dev->tcp_connected) {
            vserial_tcp_connect(dev);
            msleep(reconnect_interval * 1000);  // 使用配置的重连间隔
            continue;
        }
        
        memset(&msg, 0, sizeof(msg));
        iov.iov_base = tcp_buffer;
        iov.iov_len = sizeof(tcp_buffer);
        
        ret = kernel_recvmsg(dev->tcp_socket, &msg, &iov, 1, 
                            iov.iov_len, MSG_DONTWAIT);
        
        if (ret > 0) {
            spin_lock(&dev->buffer_lock);
            int available_space = BUFFER_SIZE - dev->data_size;
            int to_write = (ret < available_space) ? ret : available_space;
            
            if (to_write > 0) {
                int first_chunk = min(to_write, BUFFER_SIZE - dev->write_pos);
                memcpy(dev->buffer + dev->write_pos, tcp_buffer, first_chunk);
                
                if (first_chunk < to_write) {
                    memcpy(dev->buffer, tcp_buffer + first_chunk, 
                           to_write - first_chunk);
                }
                
                dev->write_pos = (dev->write_pos + to_write) % BUFFER_SIZE;
                dev->data_size += to_write;
            }
            spin_unlock(&dev->buffer_lock);
            
            wake_up_interruptible(&dev->read_queue);
        } else if (ret == -EAGAIN) {
            msleep(10);
        } else {
            printk(KERN_WARNING "vserial: TCP connection lost\n");
            dev->tcp_connected = 0;
            sock_release(dev->tcp_socket);
            dev->tcp_socket = NULL;
            msleep(reconnect_interval * 1000);  // 使用配置的重连间隔
        }
    }
    
    return 0;
}

// 文件操作
static int vserial_open(struct inode *inode, struct file *file)
{
    int minor = MINOR(inode->i_rdev);
    if (minor >= device_count || !vserial_devices[minor]) {
        return -ENODEV;
    }
    file->private_data = vserial_devices[minor];
    return 0;
}

static int vserial_release(struct inode *inode, struct file *file)
{
    return 0;
}

static ssize_t vserial_read(struct file *file, char __user *buf, 
                           size_t count, loff_t *ppos)
{
    vserial_device_t *dev = (vserial_device_t *)file->private_data;
    int ret = 0;
    int copied = 0;
    
    if (count == 0)
        return 0;
    
    ret = wait_event_interruptible(dev->read_queue, 
                                  dev->data_size > 0 || kthread_should_stop());
    if (ret)
        return ret;
    
    spin_lock(&dev->buffer_lock);
    
    if (dev->data_size > 0) {
        int to_read = min(count, dev->data_size);
        int first_chunk = min(to_read, BUFFER_SIZE - dev->read_pos);
        
        if (copy_to_user(buf, dev->buffer + dev->read_pos, first_chunk)) {
            spin_unlock(&dev->buffer_lock);
            return -EFAULT;
        }
        
        if (first_chunk < to_read) {
            if (copy_to_user(buf + first_chunk, dev->buffer, 
                           to_read - first_chunk)) {
                spin_unlock(&dev->buffer_lock);
                return -EFAULT;
            }
        }
        
        dev->read_pos = (dev->read_pos + to_read) % BUFFER_SIZE;
        dev->data_size -= to_read;
        copied = to_read;
    }
    
    spin_unlock(&dev->buffer_lock);
    
    return copied;
}

static ssize_t vserial_write(struct file *file, const char __user *buf,
                            size_t count, loff_t *ppos)
{
    vserial_device_t *dev = (vserial_device_t *)file->private_data;
    char kernel_buf[BUFFER_SIZE];
    int ret;
    
    if (count == 0)
        return 0;
    
    if (count > BUFFER_SIZE)
        count = BUFFER_SIZE;
    
    if (copy_from_user(kernel_buf, buf, count))
        return -EFAULT;
    
    if (dev->tcp_connected && dev->tcp_socket) {
        struct msghdr msg;
        struct kvec iov;
        
        memset(&msg, 0, sizeof(msg));
        iov.iov_base = kernel_buf;
        iov.iov_len = count;
        
        ret = kernel_sendmsg(dev->tcp_socket, &msg, &iov, 1, count);
        if (ret < 0) {
            printk(KERN_WARNING "vserial: Failed to send to TCP\n");
        }
    }
    
    return count;
}

static unsigned int vserial_poll(struct file *file, poll_table *wait)
{
    vserial_device_t *dev = (vserial_device_t *)file->private_data;
    unsigned int mask = 0;
    
    poll_wait(file, &dev->read_queue, wait);
    
    spin_lock(&dev->buffer_lock);
    if (dev->data_size > 0)
        mask |= POLLIN | POLLRDNORM;
    spin_unlock(&dev->buffer_lock);
    
    mask |= POLLOUT | POLLWRNORM;
    
    return mask;
}

// 实现串口相关的ioctl操作
static long vserial_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
{
    vserial_device_t *dev = (vserial_device_t *)file->private_data;
    struct termios tty;
    int ret = 0;
    
    switch (cmd) {
        case TCGETS:
            // 返回保存的串口设置，如果没有设置过则返回默认值
            if (dev->settings_initialized) {
                if (copy_to_user((struct termios __user *)arg, &dev->saved_termios, sizeof(struct termios)))
                    return -EFAULT;
            } else {
                // 返回默认设置
                memset(&tty, 0, sizeof(tty));
                tty.c_cflag = B9600 | CS8 | CLOCAL | CREAD;
                tty.c_iflag = 0;
                tty.c_oflag = 0;
                tty.c_lflag = 0;
                tty.c_cc[VMIN] = 0;
                tty.c_cc[VTIME] = 1;
                
                if (copy_to_user((struct termios __user *)arg, &tty, sizeof(tty)))
                    return -EFAULT;
            }
            break;
            
        case TCSETS:
        case TCSETSW:
        case TCSETSF:
            // 保存串口设置
            if (copy_from_user(&tty, (struct termios __user *)arg, sizeof(tty)))
                return -EFAULT;
            
            // 保存到设备结构中
            memcpy(&dev->saved_termios, &tty, sizeof(struct termios));
            dev->settings_initialized = 1;
            break;
            
        case TIOCMGET:
            // 返回调制解调器状态（总是返回连接状态）
            {
                int status = TIOCM_CTS | TIOCM_DSR | TIOCM_CD;
                if (copy_to_user((int __user *)arg, &status, sizeof(int)))
                    return -EFAULT;
            }
            break;
            
        case TIOCMSET:
            // 设置调制解调器状态（忽略）
            break;
            
        case TIOCMBIC:
        case TIOCMBIS:
            // 清除/设置调制解调器位（忽略）
            break;
            
        case TCFLSH:
            // 刷新缓冲区
            {
                int queue_selector = (int)arg;
                if (queue_selector == TCIFLUSH || queue_selector == TCIOFLUSH) {
                    spin_lock(&dev->buffer_lock);
                    dev->read_pos = dev->write_pos;
                    dev->data_size = 0;
                    spin_unlock(&dev->buffer_lock);
                }
            }
            break;
            
        default:
            // 对于不支持的ioctl，返回ENOTTY
            ret = -ENOTTY;
            break;
    }
    
    return ret;
}

static const struct file_operations vserial_fops = {
    .owner = THIS_MODULE,
    .open = vserial_open,
    .release = vserial_release,
    .read = vserial_read,
    .write = vserial_write,
    .poll = vserial_poll,
    .unlocked_ioctl = vserial_ioctl,
};

// 模块初始化
static int __init vserial_init(void)
{
    int ret, i;
    dev_t dev;
    char device_name[32];
    
    // 限制设备数量
    if (num_devices <= 0 || num_devices > MAX_DEVICES) {
        printk(KERN_ERR "vserial: Invalid number of devices: %d (max: %d)\n", 
               num_devices, MAX_DEVICES);
        return -EINVAL;
    }
    
    // 验证并调整重连间隔范围
    if (reconnect_interval < 1) {
        printk(KERN_WARNING "vserial: Reconnect interval %d too low, using 1 second\n", 
               reconnect_interval);
        reconnect_interval = 1;
    } else if (reconnect_interval > 30) {
        printk(KERN_WARNING "vserial: Reconnect interval %d too high, using 30 seconds\n", 
               reconnect_interval);
        reconnect_interval = 30;
    }
    
    ret = alloc_chrdev_region(&dev, 0, num_devices, VSERIAL_DEVICE_NAME);
    if (ret < 0) {
        printk(KERN_ERR "vserial: Failed to allocate device numbers\n");
        return ret;
    }
    vserial_major = MAJOR(dev);
    
    vserial_class = class_create(THIS_MODULE, VSERIAL_CLASS_NAME);
    if (IS_ERR(vserial_class)) {
        ret = PTR_ERR(vserial_class);
        printk(KERN_ERR "vserial: Failed to create device class\n");
        goto fail_class;
    }
    
    // 创建多个设备
    for (i = 0; i < num_devices; i++) {
        vserial_devices[i] = kzalloc(sizeof(vserial_device_t), GFP_KERNEL);
        if (!vserial_devices[i]) {
            ret = -ENOMEM;
            printk(KERN_ERR "vserial: Failed to allocate device structure %d\n", i);
            goto fail_devices;
        }
        
        cdev_init(&vserial_devices[i]->cdev, &vserial_fops);
        vserial_devices[i]->cdev.owner = THIS_MODULE;
        
        ret = cdev_add(&vserial_devices[i]->cdev, MKDEV(vserial_major, i), 1);
        if (ret < 0) {
            printk(KERN_ERR "vserial: Failed to add cdev %d\n", i);
            goto fail_cdev;
        }
        
        // 根据设备索引设置设备名
        switch (i) {
            case 0:
                strcpy(device_name, dev0_name);
                break;
            case 1:
                strcpy(device_name, dev1_name);
                break;
            case 2:
                strcpy(device_name, dev2_name);
                break;
            case 3:
                strcpy(device_name, dev3_name);
                break;
            case 4:
                strcpy(device_name, dev4_name);
                break;
            case 5:
                strcpy(device_name, dev5_name);
                break;
            case 6:
                strcpy(device_name, dev6_name);
                break;
            case 7:
                strcpy(device_name, dev7_name);
                break;
            default:
                sprintf(device_name, "ttyV%d", i);
                break;
        }
        vserial_devices[i]->device = device_create(vserial_class, NULL, 
                                                 MKDEV(vserial_major, i), NULL, device_name);
        if (IS_ERR(vserial_devices[i]->device)) {
            ret = PTR_ERR(vserial_devices[i]->device);
            printk(KERN_ERR "vserial: Failed to create device file %s\n", device_name);
            goto fail_device;
        }
        
        init_waitqueue_head(&vserial_devices[i]->read_queue);
        spin_lock_init(&vserial_devices[i]->buffer_lock);
        
        // 初始化串口设置
        vserial_devices[i]->settings_initialized = 0;
        memset(&vserial_devices[i]->saved_termios, 0, sizeof(struct termios));
        
        // 根据设备索引设置IP和端口
        switch (i) {
            case 0:
                strcpy(vserial_devices[i]->tcp_ip, dev0_ip);
                vserial_devices[i]->tcp_port = dev0_port;
                break;
            case 1:
                strcpy(vserial_devices[i]->tcp_ip, dev1_ip);
                vserial_devices[i]->tcp_port = dev1_port;
                break;
            case 2:
                strcpy(vserial_devices[i]->tcp_ip, dev2_ip);
                vserial_devices[i]->tcp_port = dev2_port;
                break;
            case 3:
                strcpy(vserial_devices[i]->tcp_ip, dev3_ip);
                vserial_devices[i]->tcp_port = dev3_port;
                break;
            case 4:
                strcpy(vserial_devices[i]->tcp_ip, dev4_ip);
                vserial_devices[i]->tcp_port = dev4_port;
                break;
            case 5:
                strcpy(vserial_devices[i]->tcp_ip, dev5_ip);
                vserial_devices[i]->tcp_port = dev5_port;
                break;
            case 6:
                strcpy(vserial_devices[i]->tcp_ip, dev6_ip);
                vserial_devices[i]->tcp_port = dev6_port;
                break;
            case 7:
                strcpy(vserial_devices[i]->tcp_ip, dev7_ip);
                vserial_devices[i]->tcp_port = dev7_port;
                break;
            default:
                strcpy(vserial_devices[i]->tcp_ip, tcp_server_ip);
                vserial_devices[i]->tcp_port = tcp_server_port + i;
                break;
        }
        vserial_devices[i]->tcp_connected = 0;
        
        sprintf(device_name, "vserial_tcp_%d", i);
        vserial_devices[i]->tcp_thread = kthread_run(vserial_tcp_thread, vserial_devices[i], device_name);
        if (IS_ERR(vserial_devices[i]->tcp_thread)) {
            ret = PTR_ERR(vserial_devices[i]->tcp_thread);
            printk(KERN_ERR "vserial: Failed to create TCP thread %d\n", i);
            goto fail_thread;
        }
        
        device_count++;
        printk(KERN_INFO "vserial: Created device %s (TCP port: %d)\n", 
               device_name, vserial_devices[i]->tcp_port);
    }
    
    // 创建proc文件用于状态查看
    create_proc_files();
    
    printk(KERN_INFO "vserial: Virtual serial driver loaded with %d devices\n", device_count);
    printk(KERN_INFO "vserial: TCP server base: %s:%d\n", tcp_server_ip, tcp_server_port);
    printk(KERN_INFO "vserial: Reconnect interval: %d seconds\n", reconnect_interval);
    printk(KERN_INFO "vserial: Status available at /proc/vserial_stj/status\n");
    return 0;
    
fail_thread:
    device_destroy(vserial_class, MKDEV(vserial_major, i));
fail_device:
    cdev_del(&vserial_devices[i]->cdev);
fail_cdev:
    kfree(vserial_devices[i]);
fail_devices:
    // 清理已创建的设备
    for (int j = 0; j < i; j++) {
        if (vserial_devices[j]) {
            if (vserial_devices[j]->tcp_thread && !IS_ERR(vserial_devices[j]->tcp_thread)) {
                kthread_stop(vserial_devices[j]->tcp_thread);
            }
            if (vserial_devices[j]->tcp_socket) {
                sock_release(vserial_devices[j]->tcp_socket);
            }
            if (vserial_devices[j]->device) {
                device_destroy(vserial_class, MKDEV(vserial_major, j));
            }
            cdev_del(&vserial_devices[j]->cdev);
            kfree(vserial_devices[j]);
        }
    }
    class_destroy(vserial_class);
fail_class:
    unregister_chrdev_region(MKDEV(vserial_major, 0), num_devices);
    return ret;
}

// 状态查看相关
static struct proc_dir_entry *vserial_proc_dir = NULL;

// 显示设备状态的seq_file操作
static int vserial_status_show(struct seq_file *m, void *v)
{
    int i;
    
    seq_printf(m, "=== 虚拟串口状态 ===\n");
    seq_printf(m, "模块版本: 1.0\n");
    seq_printf(m, "设备数量: %d\n", device_count);
    seq_printf(m, "重连间隔: %d 秒\n", reconnect_interval);
    seq_printf(m, "\n");
    
    for (i = 0; i < device_count; i++) {
        vserial_device_t *dev = vserial_devices[i];
        if (!dev) continue;
        
        seq_printf(m, "设备 %d:\n", i);
        seq_printf(m, "  设备名: %s\n", dev->device ? dev_name(dev->device) : "未知");
        seq_printf(m, "  TCP地址: %s:%d\n", dev->tcp_ip, dev->tcp_port);
        seq_printf(m, "  TCP状态: %s\n", dev->tcp_connected ? "已连接" : "未连接");
        seq_printf(m, "  TCP线程: %s\n", dev->tcp_thread ? "运行中" : "已停止");
        seq_printf(m, "  缓冲区: %d/%d 字节\n", dev->data_size, BUFFER_SIZE);
        seq_printf(m, "  设置已保存: %s\n", dev->settings_initialized ? "是" : "否");
        seq_printf(m, "\n");
    }
    
    return 0;
}

static int vserial_status_open(struct inode *inode, struct file *file)
{
    return single_open(file, vserial_status_show, NULL);
}

static const struct proc_ops vserial_status_fops = {
    .proc_open = vserial_status_open,
    .proc_read = seq_read,
    .proc_lseek = seq_lseek,
    .proc_release = single_release,
};

// 创建proc文件
static void create_proc_files(void)
{
    vserial_proc_dir = proc_mkdir("vserial_stj", NULL);
    if (!vserial_proc_dir) {
        printk(KERN_ERR "vserial: Failed to create proc directory\n");
        return;
    }
    
    if (!proc_create("status", 0444, vserial_proc_dir, &vserial_status_fops)) {
        printk(KERN_ERR "vserial: Failed to create status proc file\n");
    }
}

// 清理proc文件
static void remove_proc_files(void)
{
    if (vserial_proc_dir) {
        remove_proc_entry("status", vserial_proc_dir);
        remove_proc_entry("vserial_stj", NULL);
    }
}

// 模块清理
static void __exit vserial_exit(void)
{
    int i;
    
    // 清理proc文件
    remove_proc_files();
    
    // 清理所有设备
    for (i = 0; i < device_count; i++) {
        if (vserial_devices[i]) {
            if (vserial_devices[i]->tcp_thread && !IS_ERR(vserial_devices[i]->tcp_thread)) {
                kthread_stop(vserial_devices[i]->tcp_thread);
            }
            
            if (vserial_devices[i]->tcp_socket) {
                sock_release(vserial_devices[i]->tcp_socket);
            }
            
            if (vserial_devices[i]->device) {
                device_destroy(vserial_class, MKDEV(vserial_major, i));
            }
            
            cdev_del(&vserial_devices[i]->cdev);
            kfree(vserial_devices[i]);
        }
    }
    
    if (vserial_class) {
        class_destroy(vserial_class);
    }
    
    if (vserial_major) {
        unregister_chrdev_region(MKDEV(vserial_major, 0), device_count);
    }
    
    printk(KERN_INFO "vserial: Virtual serial driver unloaded (%d devices)\n", device_count);
}

module_init(vserial_init);
module_exit(vserial_exit); 